import abc
import json
from datetime import time
from pathlib import Path
import shutil

import requests
from pptx import Presentation

from config import *
from modules.tts_ws import text_to_mp3


class GenerateVideoBase(object):
    script_data = None
    res_id = None
    output_video_file = None
    temp_store_path = None
    api_host = None
    generate_result = {}
    ppt_tpl_path = None

    def __init__(self, res_id, ppt_tpl_path):
        self.res_id = res_id
        self.ppt_tpl_path = ppt_tpl_path

    @abc.abstractmethod
    def fetch_script_data(self):
        """
        获取数据
        :return:
        """
        pass

    @abc.abstractmethod
    def handle_spec_slide(self, page_no, slide, model):
        """
        处理异常数据
        :param page_no: 页号
        :param slide: 幻灯片的每页实例
        :param model: 对应的模型数据
        :return:
        """
        pass

    def del_file(self, path_data):
        for i in os.listdir(path_data):  # os.listdir(path_data)#返回一个列表，里面是当前目录下面的所有东西的相对路径
            file_data = path_data + os.sep + i  # 当前文件夹的下面的所有东西的绝对路径
            if os.path.isfile(file_data) == True:  # os.path.isfile判断是否为文件,如果是文件,就删除.如果是文件夹.递归给del_file.
                os.remove(file_data)
            else:
                self.del_file(file_data)

    def generate(self):
        # start_time = time.time()
        self.temp_store_path = TEMP_PATH + self.res_id + os.sep
        # 清空此目录
        try:
            self.del_file(self.temp_store_path)
        except Exception as e:
            pass
        # 创建临时目录
        if not os.path.exists(self.temp_store_path):
            os.makedirs(self.temp_store_path)

        if not os.path.exists(self.temp_store_path + 'pics' + os.sep):
            os.makedirs(self.temp_store_path + 'pics' + os.sep)
        if not os.path.exists(self.temp_store_path + 'mp3s' + os.sep):
            os.makedirs(self.temp_store_path + 'mp3s' + os.sep)

        item = json.loads(self.script_data['data'])
        datas = item['data']

        # 音频生成
        txts = []
        for i in range(len(datas)):
            txts.append(datas[i]['src']) # audio_text
        for i in range(len(txts)):
            text_to_mp3(self.temp_store_path + 'mp3s' + os.sep + "1-{}.mp3".format(str(i+1)), txts[i])
            # 需要分割成多句生成语音的：
            txts_sub = txts[i].split('|')
            if len(txts_sub) > 1:
                for j in range(len(txts_sub)):
                    text_to_mp3(self.temp_store_path + 'mp3s' + os.sep + "1-{}-{}.mp3".format(str(i + 1), str(j + 1)), txts_sub[j])
        # 下载音效
        if (item['audio_start'] != ""):
            file_path = self.temp_store_path + 'mp3s' + os.sep + 'audio_start.mp3'
            with open(file_path, 'wb') as f:
                response = requests.get(item['audio_start'])
                f.write(response.content)
        if (item['audio_end'] != ""):
            file_path = self.temp_store_path + 'mp3s' + os.sep + 'audio_end.mp3'
            with open(file_path, 'wb') as f:
                response = requests.get(item['audio_end'])
                f.write(response.content)
        print('音频生成完毕.')

        # 下载图片
        if not os.path.exists(MP4_PATH):
            os.makedirs(MP4_PATH)
        for i in range(len(datas)):
            file_ext = datas[i]['img_url'][-4:]
            file_path = self.temp_store_path + 'pics' + os.sep + str(i+1) + '-1' + ('.mp4' if file_ext == '.mp4' else '.jpg')
            if (file_ext == '.mp4'):
                # 视频文件缓存防止重复下载
                # http://dfs.films.cn/file/5fc862d2b18fbb2513fb6cfd.mp4
                # shutil.copyfile(video_path, target_path)
                # if my_file.is_file():
                filemp4 = MP4_PATH + datas[i]['img_url'][datas[i]['img_url'].rfind('/') + 1:]
                f_filemp4 = Path(filemp4)
                if not f_filemp4.is_file():
                    with open(filemp4, 'wb') as f:
                        response = requests.get(datas[i]['img_url'])
                        f.write(response.content)
                else:
                    print('已缓存')
                shutil.copyfile(filemp4, file_path)
            else:
                with open(file_path, 'wb') as f:
                    response = requests.get(datas[i]['img_url'])
                    image_byte = response.content
                    f.write(response.content)
                    # print("download img {} and save to {} success".format(img_url, file_path))

            if ('chart_url' in datas[i]):
                chart_url = datas[i]['chart_url']
                if (chart_url != None and len(chart_url) > 0):
                    file_path = self.temp_store_path + 'pics' + os.sep + str(i + 1) + '-1-chart.png'
                    with open(file_path, 'wb') as f:
                        response = requests.get(datas[i]['chart_url'])
                        image_byte = response.content
                        f.write(response.content)

        # 下载图表
        print('图片资源完毕')

        # 更新状态6
        requests.get(url=self.api_host + '/v1/pic/edit_news_scripts_status/' + self.res_id + '/6')
        print('更新状态6')


        return 0

        # prs = Presentation(self.ppt_tpl_path)
        # page_video_paths = list()
        # # 生成每页的视频文件
        # for page_no in range(0, len(prs.slides)):
        #     if not self.script_data[page_no]['model']:
        #         continue
        #     # 1.生成临时的ppt文件
        #     ppt_file_path = self.generate_page_ppt(page_no)
        #     # 2.生成音频文件
        #     audio_file_path = self.generate_page_audio(page_no)
        #     # 3.将视频和音频合并成一个文件
        #     output_path = self.temp_store_path + 'page_' + str(page_no) + '.mp4'
        #     self.ppt_to_video(ppt_file_path, audio_file_path, output_path)
        #     page_video_paths.append(output_path)
        # # 合并所有的的视频信息
        # video_path = self.temp_store_path + 'video.mp4'
        # video_screenshot_path = self.temp_store_path + 'video.png'
        # # 合并成最终文件
        # video_concat_by_file(page_video_paths, self.temp_store_path, video_path)

        # # 获取文件信息
        # video_media_info = media_info(video_path)
        # print("media info {}".format(video_media_info))
        # # 生成截图信息
        # screenshot_video(video_path, video_screenshot_path, ss='00:00:02')
        # print("generate {} screenshot success ".format(video_path))

        # duration = float(video_media_info['duration'])

        # end_time = time.time()
        # cost_time = round(end_time - start_time, 2)
        # print("generate {} success cost {}s".format(video_path, cost_time))

        # # 记录值生成结果中
        # self.generate_result['video_path'] = video_path
        # self.generate_result['video_screenshot_path'] = video_screenshot_path
        # self.generate_result['duration'] = duration
        # return self.generate_result

    def generate_page_ppt(self, page_no):
        prs = Presentation(self.ppt_tpl_path)
        slide = prs.slides[page_no]

        model = {}
        model = self.script_data[page_no]['model']
        # 处理文本内容
        for shape in slide.shapes:
            self.render_text_frame(shape, model)

        # 特殊处理，主要是针对每页的图片做替换
        self.handle_spec_slide(page_no, slide, model)

        # 删除其他页的数据
        r_id = prs.slides._sldIdLst[page_no].rId
        while len(prs.slides) > 1:
            for i in range(0, len(prs.slides)):
                now_r_id = prs.slides._sldIdLst[i].rId
                if r_id != now_r_id:
                    prs.part.drop_rel(now_r_id)
                    del prs.slides._sldIdLst[i]
                    break
        ppt_file_path = self.temp_store_path + 'page_temp_{}.pptx'.format(page_no)
        prs.save(ppt_file_path)
        print("generate {} success".format(ppt_file_path))
        return ppt_file_path

    def replace_image(self, slide, pic_shape, img_url):
        if not os.path.exists(TEMP_IMAGE_PATH):
            os.mkdir(TEMP_IMAGE_PATH)
        file_path = TEMP_IMAGE_PATH + img_url.split('/')[-1]
        with open(file_path, 'wb') as f:
            response = requests.get(img_url)
            image_byte = response.content
            f.write(response.content)
            print("download img {} and save to {} success".format(img_url, file_path))
        img_rid = pic_shape._pic.xpath('./p:blipFill/a:blip/@r:embed')[0]
        img_part = slide.part.related_parts[img_rid]
        img_part._blob = image_byte

    def replace_local_image(self, slide, pic_shape, image_local_path):
        if not os.path.exists(TEMP_IMAGE_PATH):
            os.mkdir(TEMP_IMAGE_PATH)
        with open(image_local_path, 'rb') as f:
            image_byte = f.read()
        img_rid = pic_shape._pic.xpath('./p:blipFill/a:blip/@r:embed')[0]
        img_part = slide.part.related_parts[img_rid]
        img_part._blob = image_byte

    def generate_page_audio(self, page_no):
        audio_text = self.script_data[page_no]['audio_text']
        audio_file_path = self.temp_store_path + 'page_temp_{}.mp3'.format(page_no)
        text_to_mp3(audio_file_path, audio_text)
        print("generate {} success".format(audio_file_path))
        return audio_file_path

    def render_text_frame(self, shape, model):
        if shape.has_text_frame:
            text = shape.text
            for key in model.keys():
                replace_key = "${" + key + "}"
                if replace_key in text:
                    replace_text = text.replace(replace_key, model[key])
                    shape.text_frame.paragraphs[0].runs[0].text = replace_text
                    print("{} 替换成功 {}".format(text, replace_text))
        if 'pptx.shapes.group.GroupShape' in str(type(shape)):
            for shape in shape.shapes:
                self.render_text_frame(shape, model)

    # 导出视频
    def ppt_to_video(self, ppt_path, mp3_path, output_path):
        # 获取MP3时长
        duration = int(float(media_info(mp3_path, 'duration')))
        # pptx生成视频
        mp4_path = output_path + '.temp'
        cover_ppt_to_mp4(ppt_path, mp4_path, duration)
        # 音频和视频合成
        output = video_audio_concat(mp4_path, mp3_path, output_path)
        os.remove(mp4_path)
        return output
